﻿package fr.babos.test.data
{
	import flash.display.Sprite;
	import flash.utils.getTimer;
	import flash.utils.setTimeout;
	import fr.babos.core.data.parse.DataParser;
	import fr.babos.core.data.collect.DataCollection;
	import fr.babos.core.data.collect.IDataCollection;
	import fr.babos.core.data.managers.DataIterator;
	import fr.babos.core.data.managers.DisplayBuilder;
	import fr.babos.core.data.managers.IDataFilter;
	import fr.babos.core.data.managers.IDataIterator;
	import fr.babos.core.data.remote.ADataRemote;
	import fr.babos.core.data.remote.AMFRemote;
	import fr.babos.core.data.remote.IDataRemote;
	import fr.babos.core.data.remote.RemotingCall;
	import fr.babos.core.data.remote.XMLRemote;
	import fr.babos.core.log.Log;
	import fr.babos.core.log.MonsterLogger;
	import fr.babos.core.log.TraceLogger;
	import fr.babos.test.data.items.AccountItem;
	import fr.babos.test.data.items.PlaceItem;
	import fr.babos.test.data.items.UserItem;
	
	/**
	 * Classe de test de la partie fr.babos.core.data
	 * @author ZoulouX
	 */
	public class BabosDataTest extends Sprite
	{
		private var _AMFRemote:IDataRemote;
		private var _usersCollection:DataCollection;
		/**
		 * Le constructeur
		 */
		public function BabosDataTest ()
		{
			Log.log("-- BABOS DATA TEST --");
			
			// Initialiser le logger
			Log.addLogger(new TraceLogger());
			Log.addLogger(new MonsterLogger(this));
			
			// Test sur les classes de données (collection, itérateurs, filtres, parseur...)
			//dataCollectionTest();
			//dataIteratorTest();
			//dataFilterTest();
			//displayBuilderTest();
			//dataParserTest();
			//adaptersTest();
			//dataParserBench();
			
			// Test sur les remotes
			//setTimeout(AMFRemoteTest, 500);
			//setTimeout(XMLRemoteTest, 500);
			setTimeout(XMLRemoteTest2, 500);
			//setTimeout(JSONRemoteTest, 500);
		}
		
		/**
		 * DataCollection.forEach handler
		 * @param	pItem
		 * @param	pIndex
		 */
		public function showItemHandler (pItem:BabosDataTestItem, pIndex:uint):void
		{
			// Scope / index / item
			Log.log(this + ", " + pIndex + ": " + pItem);
		}
		
		/**
		 * Test des collections
		 */
		public function dataCollectionTest ():void
		{
			Log.log("DATA COLLECTION TEST");
			
			// Créer la collection et la remplir d'items
			var collection:IDataCollection = new DataCollection(null, 
				[
					new BabosDataTestItem(1, "Test 1"),
					new BabosDataTestItem(2, "Test 2"),
					new BabosDataTestItem(3, "Test 3"),
					new BabosDataTestItem(4, "Test 4"),
					new BabosDataTestItem(5, "Test 5")
				]
			);
			
			// toString
			Log.log("ToString: " + collection);
			Log.log("---------------");
			
			// Length
			Log.log("Length: " + collection.length);
			Log.log("---------------");
			
			// First
			Log.log("The first element");
			Log.log(collection.first as BabosDataTestItem);
			Log.log("---------------");
			
			// Last
			Log.log("The last element");
			Log.log(collection.last as BabosDataTestItem);
			Log.log("---------------");
			
			// forEach
			Log.log("All the elements with collection.forEach");
			collection.forEach(showItemHandler);
			Log.log("---------------");
			
			// All
			Log.log("All the elements with collection.all");
			for each (var item:BabosDataTestItem in collection.all)
			{
				Log.log(item);
			}
			Log.log("---------------");
			
			// RemoveAt
			Log.log("Deleting index 2");
			collection.removeAt(2);
			collection.forEach(showItemHandler);
			Log.log("---------------");
			
			// Remove
			Log.log("Deleting an element, the first");
			collection.remove(collection.first);
			collection.forEach(showItemHandler);
			Log.log("---------------");
			
			// Add
			Log.log("Adding an element");
			collection.add(new BabosDataTestItem(0, "An element"));
			collection.forEach(showItemHandler);
			Log.log("---------------");
			
			// AddAt
			Log.log("Adding an element at 2");
			collection.addAt(new BabosDataTestItem(10, "An other element"), 2);
			collection.forEach(showItemHandler);
			Log.log("---------------");
			
			// Sort
			Log.log("Sorting by id");
			collection.sort(["id"]);
			collection.forEach(showItemHandler);
			
			// Sort
			Log.log("Sorting by id DESC");
			collection.sort(["id"], false);
			collection.forEach(showItemHandler);
			
			// Sort
			Log.log("Sorting by values");
			collection.sort(["value"], true, false, false);
			collection.forEach(showItemHandler);
			
			// Filter
			Log.log("Filtering by id (id < 3)");
			collection.filterCollection(function (pObject:BabosDataTestItem, pIndex:uint, pArray:Array):Boolean {
				return (pObject.id < 3)
			});
			collection.forEach(showItemHandler);
		}
		
		/**
		 * Test des itérators
		 */
		protected function dataIteratorTest ():void
		{
			Log.log("DATA ITERATOR TEST");
			
			// Créer la collection et la remplir d'items
			var collection:IDataCollection = new DataCollection(null, 
				[
					new BabosDataTestItem(1, "Test 1"),
					new BabosDataTestItem(2, "Test 2"),
					new BabosDataTestItem(3, "Test 3"),
					new BabosDataTestItem(4, "Test 4"),
					new BabosDataTestItem(5, "Test 5")
				]
			);
			
			// Créer l'iterator
			var iterator:IDataIterator = new DataIterator(collection);
			
			// Le premier élément
			Log.log("Current");
			Log.log(iterator.index+": "+iterator.current);
			
			// 
			Log.log("Iterating step by step");
			while (iterator.hasNext())
			{
				Log.log(iterator.next()+": " +iterator.index);
			}
			
			Log.log("end: " + iterator.index + ": " + iterator.current);
			
			Log.log("reset");
			iterator.reset();
			
			Log.log("start: "+iterator.index+": "+iterator.current);
			
			Log.log("Reiterating")
			while (iterator.hasNext())
			{
				Log.log(iterator.next()+": " +iterator.index);
			}
			Log.log("end: " + iterator.index + ": " + iterator.current);
			Log.log("Go to end");
			
			iterator.goToEnd();
			
			Log.log("Reverse iterating");
			while (iterator.hasPrev())
			{
				Log.log(iterator.prev()+": " +iterator.index);
			}
			Log.log("end: " + iterator.index + ": " + iterator.current);
			
			
			Log.log("normal looping");
			iterator.loop = true;
			
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log(iterator.next());
			Log.log("end loop");
			
			Log.log("reverse looping");
			
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log(iterator.prev());
			Log.log("end loop");
		}
		
		/**
		 * Test des filters
		 */
		protected function dataFilterTest ():void
		{
			Log.log("DATA FILTER TEST");
			
			// Créer la collection
			var collection:IDataCollection = new DataCollection(null, [
				new BabosDataTestItem(1, "Test 1"),
				new BabosDataTestItem(2, "Test 2"),
				new BabosDataTestItem(3, "Test 3"),
				new BabosDataTestItem(4, "Test 4"),
				new BabosDataTestItem(5, "Test 5"),
				new BabosDataTestItem(6, "Test 6")
			]);
			
			// Créer le filtre
			var filter:BabosDataFilter = new BabosDataFilter(collection);
			
			// Afficher la collection
			Log.log("Complete collection");
			collection.forEach(showItemHandler);
			
			// Filtrer avec le custom
			Log.log("Custom filter method with id >= 3 & id <= 5");
			filter.filterById(3, 5).forEach(showItemHandler);
			
			// Filtrer avec le custom
			Log.log("External filter method with id <= 3 && id >= 0");
			filter.startId = 0;
			filter.endId = 3;
			filter.filter();
			filter.filteredCollection.forEach(showItemHandler);
		}
		
		/**
		 * Test des builder graphiques
		 */
		public function displayBuilderTest ():void
		{
			Log.log("DISPLAY BUILDER TEST");
			
			// Créer la collection
			var collection:IDataCollection = new DataCollection(null, [
				new BabosDataTestItem(1, "Test 1"),
				new BabosDataTestItem(2, "Test 2"),
				new BabosDataTestItem(3, "Test 3"),
				new BabosDataTestItem(4, "Test 4"),
				new BabosDataTestItem(5, "Test 5"),
				new BabosDataTestItem(6, "Test 6")
			]);
			
			// Construire la liste graphique
			DisplayBuilder.build(collection, BabosDisplayTest, displayBuildHandler, null, this);
		}
		
		/**
		 * Construire un élément graphique
		 * @param	pDisplayObject : L'élément graphique instancié
		 * @param	pItem : L'item associé
		 * @param	pIndex : L'index de l'item
		 */
		public function displayBuildHandler (pDisplayObject:BabosDisplayTest, pItem:BabosDataTestItem, pIndex:uint):void
		{
			Log.log("adding item: " + pItem + ", " + pIndex);
			
			// Placer
			pDisplayObject.x = 10;
			pDisplayObject.y = pIndex * 40 + 10;
		}
		
		/**
		 * Test des parsers
		 */
		public function dataParserTest ():void
		{
			Log.log("DATA PARSER TEST");
			
			// Les données brutes
			var xmlData:XML = <root>
				<babosItem id="1">
					<value>Parsing Test 1 from XML</value>
				</babosItem>
				<babosItem id="2">
					<value>Parsing Test 2 from XML</value>
				</babosItem>
				<babosItem id="3">
					<value>Parsing Test 3 from XML</value>
				</babosItem>
				<babosItem id="4">
					<value>Parsing Test 4 from XML</value>
				</babosItem>
			</root>;
			
			// Les données JSON
			var jsonData:Object = [
				{"babosItem" : {
					id: 1,
					value: "Parsing Test 1 from JSON"
				}},
				{"babosItem" : {
					id: 2,
					value: "Parsing Test 2 from JSON"
				}}
			];
			
			// Créer la collection vide
			var collection:IDataCollection = new DataCollection();
			
			// Créer le parseur
			var dataParser:DataParser = new DataParser();
			
			// Ajouter les éléments à parser
			dataParser.addItemType("babosItem", BabosDataTestItem);
			
			// Parser depuis le fichier XML
			DataParser.feedCollection(collection, dataParser.parse(xmlData), BabosDataTestItem);
			
			// Afficher la collection
			Log.log("Parsing from XML "+xmlData);
			collection.forEach(showItemHandler);
			
			// On vide la collection
			collection.clear();
			
			// Parser depuis un objet JSON
			DataParser.feedCollection(collection, dataParser.parse(jsonData), BabosDataTestItem);
			
			// Afficher la collection
			Log.log("Parsing from JSON or AMF"+jsonData);
			collection.forEach(showItemHandler);
		}
		
		/**
		 * Test des parsers 2
		 */
		public function dataParserTest2 ():void
		{
			// Les données brutes
			var xmlData:XML = <root>
				<babos>
					<item id="1" value="Parsing Test 1 from XML" />
					<item id="2" value="Parsing Test 2 from XML" />
					<item id="3" value="Parsing Test 3 from XML" />
					<item id="4" value="Parsing Test 4 from XML" />
					<item id="5" value="Parsing Test 5 from XML" />
					<item id="6" value="Parsing Test 6 from XML" />
					<item id="7" value="Parsing Test 7 from XML" />
				</babos>
			</root>;
			
			// Les données JSON
			var jsonData:Object = [
				{
					id: 1,
					value: "Parsing Test 1 from JSON"
				},
				{
					id: 2,
					value: "Parsing Test 2 from JSON"
				},
				{
					id: 3,
					value: "Parsing Test 3 from JSON"
				}
			];
			
			
		}
		
		/**
		 * Test des adapters
		 */
		public function adaptersTest ():void
		{
			Log.log("ADAPTERS TEST");
			
			// Les données XML à adapter
			var xmlData:XML = <root>
				<babos id="5">
					<content>Adaptation Test 1 from XML</content>
				</babos>
				<babos uid="4">
					<content>Adaptation Test 2 from XML</content>
					<otherBabos time="2008-12-03">
						<uid>6</uid>
					</otherBabos>
				</babos>
			</root>;
			
			// Les données JSON
			var jsonData:Object = [
				{babos : {
					id: 1,
					content: "Adaptation test 1 from JSON"
				}},
				{babos : {
					id: 2,
					content: "Adaptation test 2 from JSON",
					otherBabos: {
						uid: 6,
						time: '2010-6-10'
					}
				}}
			];
			
			// Créer la collection vide
			var collection:IDataCollection = new DataCollection();
			
			// Créer le parseur
			var dataParser:DataParser = new DataParser();
			
			// Ajouter les éléments à parser et les adapters
			dataParser.addItemType("babos", BabosDataTestItem, {
				id: 'uid',
				value: 'content',
				child: 'otherBabos'
			});
			dataParser.addItemType("otherBabos", BabosDataTestItem2, {
				id: 'uid',
				date: 'time'
			});
			
			// Parser depuis le fichier XML
			Log.log("Adapting from XML " + xmlData);
			DataParser.feedCollection(collection, dataParser.parse(xmlData), BabosDataTestItem);
			
			// Afficher la collection
			collection.forEach(showItemHandler);
			Log.log("END");
			
			// On vide la collection
			collection.clear();
			
			// Parser depuis un objet JSON
			Log.log("Adapting from JSON or AMF " + jsonData);
			DataParser.feedCollection(collection, dataParser.parse(jsonData), BabosDataTestItem);
			
			// Afficher la collection
			collection.forEach(showItemHandler);
			Log.log("END");
		}
		
		/**
		 * Benchmark des parsers
		 */
		public function dataParserBench ():void
		{
			Log.log("DATA PARSER BENCH");
			
			// Les données XML à adapter
			var xmlData:XML = <root>
				<babos id="5">
					<content>Adaptation Test 1 from XML</content>
				</babos>
				<babos uid="4">
					<content>Adaptation Test 2 from XML</content>
					<otherBabos time="2008-12-03">
						<uid>6</uid>
					</otherBabos>
				</babos>
			</root>;
			
			// Les données JSON
			var jsonData:Object = [
				{babos : {
					id: 1,
					content: "Adaptation test 1 from JSON"
				}},
				{babos : {
					id: 2,
					content: "Adaptation test 2 from JSON",
					otherBabos: {
						uid: 6,
						time: '2010-6-10'
					}
				}}
			];
			
			// Créer la collection vide
			var collection:IDataCollection = new DataCollection();
			
			// Créer le parser
			var dataParser:DataParser = new DataParser();
			
			// Ajouter les éléments à parser et les adapters
			dataParser.addItemType("babos", BabosDataTestItem, {
				id: 'uid',
				value: 'content',
				child: 'otherBabos'
			});
			dataParser.addItemType("otherBabos", BabosDataTestItem2, {
				id: 'uid',
				date: 'time'
			});
			
			// Afficher les anciennes stats
			Log.log("Old parse XML method: ~547ms / 5000 iterations");
			Log.log("Old parse JSON method: ~804ms / 5000 iterations");
			
			// Les nouvelles stats
			Log.log("New parse XML method: ~525ms / 5000 iterations");
			Log.log("New parse JSON method: ~737ms / 5000 iterations");
			
			Log.log("Started...");
			
			// Initialiser les variables et le timer
			var totalTime:Number;
			var startTime:Number = getTimer();
			var i:int;
			
			// Parser 5000 fois
			for (i = 0; i < 5000; i++) 
			{
				// Vider la collection
				collection.clear();
				
				// Parser et ajouter
				DataParser.feedCollection(collection, dataParser.parse(xmlData), BabosDataTestItem);
			}
			
			// Mesurer le temps que ça a pris
			totalTime = getTimer() - startTime;
			
			// Afficher le résultat
			Log.log("END");
			Log.log("Total time: " + totalTime + " ms");
			
			// Et la collection contenant les items parsés et adaptés
			Log.log("Collection state:");
			collection.forEach(showItemHandler);
		}
		
		/**
		 * Test de la remote AMF
		 */
		public function AMFRemoteTest ():void
		{
			Log.log("AMFRemoteTest");
			
			// Créer la remote et se connecter au serveur de Familiz
			// Liste des services disponibles : http://mobile.familiz.fr/data/cpamf/browser/
			_AMFRemote = new AMFRemote("http://mobile.familiz.fr/data/cpamf/gateway/");
			
			// Ajouter un parser à la remote
			_AMFRemote.parser = new DataParser();
			//_AMFRemote.parser.strict = false;
			
			// Spécifier les règles de parsing
			_AMFRemote.parser.addItemType("User", UserItem, {
				accounts: 'Account'
			});
			_AMFRemote.parser.addItemType("Account", AccountItem, {
				users: 'Users'
			});
			_AMFRemote.parser.addItemType("Place", PlaceItem);
			
			// Test le service de login
			_AMFRemote.call(
				'AccountsController.logTablet', {
					onSuccess: AMFServiceLogSuccessHandler,
					onError: AMFRemoteErrorHandler
				},
				3,
				'14f4dd686ccfff93b43fb98427172509'
			);
		}
		
		/**
		 * Réussite de l'appel AMF de login
		 */
		protected function AMFServiceLogSuccessHandler (pCall:RemotingCall = null):void
		{
			Log.debug("AMFServiceLogSuccessHandler", pCall.data);
			
			// La collection de users qui va être remplie
			_usersCollection = new DataCollection(UserItem);
			
			// Test le service de login
			_AMFRemote.call(
				'UsersController.getAll', {
					onSuccess: AMFServiceGetUsersSuccessHandler,
					onError: AMFRemoteErrorHandler,
					collectionToFeed: _usersCollection
				}
			);
		}
		
		/**
		 * Réussite de l'appel AMF de récupération des users
		 */
		protected function AMFServiceGetUsersSuccessHandler (pCall:RemotingCall):void
		{
			Log.debug("AMFServiceGetUsersSuccessHandler", _usersCollection.data);
		}
		
		/**
		 * Echec d'un appel AMF
		 */
		protected function AMFRemoteErrorHandler (pCall:RemotingCall):void
		{
			Log.error("AMFRemoteErrorHandler");
			Log.debug("FAIL DATA", pCall.data);
		}
		
		/**
		 * Test de la remote XML
		 */
		public function XMLRemoteTest ():void
		{
			Log.log("XMLRemoteTest");
			
			// Créer une collection vide
			var collection:DataCollection = new DataCollection();
			
			// Créer une remote
			var remote:XMLRemote = new XMLRemote();
			
			// Configurer le parseur
			remote.parser = new DataParser();
			remote.parser.addItemType("babos", BabosDataTestItem);
			
			// Faire l'appel
			remote.call("xml/babos-test.xml", {
				onSuccess: function (pCall:RemotingCall):void
				{
					Log.debug("XML SUCCESS", pCall);
					Log.debug("COLLECTION", collection.all);
				},
				collectionToFeed: collection,
				collectionFeedType: BabosDataTestItem
			});
		}
		
		/**
		 * Test de la remote XML 2
		 */
		public function XMLRemoteTest2 ():void
		{
			Log.log("XMLRemoteTest2");
			
			// Créer une collection vide
			var collection:DataCollection = new DataCollection(BabosDataTestItem2);
			
			// Créer une remote
			var remote:XMLRemote = new XMLRemote();
			
			// Configurer le parseur
			remote.parser = new DataParser();
			remote.parser.addItemType("babos", BabosDataTestItem2, {
				//babosCollections : "*"
				babosCollections : "item"
			});
			
			// Faire l'appel
			remote.call("xml/babos-test-2.xml", {
				onSuccess: function (pCall:RemotingCall):void
				{
					Log.debug("XML SUCCESS", pCall);
					Log.debug("COLLECTION", collection.data);
				},
				collectionToFeed: collection
			});
		}
		
		/**
		 * Test de la remote JSON
		 */
		public function JSONRemoteTest ():void
		{
			Log.log("JSONRemoteTest");
		}
		
		/**
		 * Test de la remote ExternalInterface
		 */
		public function ExternalInterfaceRemoteTest ():void
		{
			Log.log("ExternalInterfaceRemoteTest");
		}
	}
}